Skip to content

read DNS RDLENGTH as an unsigned 16-bit value - #9548

Merged
swankjesse merged 1 commit into
lysine-dev:mainfrom
basavaraj-sm05:dns-rdlength-unsigned
Jul 29, 2026
Merged

read DNS RDLENGTH as an unsigned 16-bit value#9548
swankjesse merged 1 commit into
lysine-dev:mainfrom
basavaraj-sm05:dns-rdlength-unsigned

Conversation

@basavaraj-sm05

Copy link
Copy Markdown
Contributor

readResourceRecord pulls the record data length out of the RDLENGTH field, which RFC 1035 defines as an unsigned 16-bit integer, but it decodes that field with readShort().toLong(), so any length with the high bit set comes back negative. Every other 16-bit field in this reader already goes through toUShort(), so this one is the odd one out. For an A or AAAA record the wrong sign is caught by the exact-length check, but for a record type we don't decode the code falls into skip(recordDataLength), and okio's skip treats a negative count as a no-op rather than an error. That means a record legitimately carrying 32768 or more bytes never gets consumed, the reader stays parked in the middle of the message, and the leftover bytes either trip the trailing-data check or get read as the next record. I hit it while feeding the reader a response with a large unknown record sitting in front of an A record. Decoding the field as unsigned, the same way the counts and the HTTPS parameter lengths already are, keeps the stream in sync, and I added a regression test that reads a message with an oversized unsupported record.

@JakeWharton
JakeWharton requested a review from swankjesse July 15, 2026 13:09

@swankjesse swankjesse left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test!

val `class` = readShort().toInt()
val timeToLive = readInt()
val recordDataLength = readShort().toLong()
val recordDataLength = readShort().toUShort().toLong()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
val recordDataLength = readShort().toUShort().toLong()
val recordDataLength = readUShort().toLong()

(also needs an import)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried this and it doesn't compile, readUShort isn't in okio yet. I checked 3.17.0 (what this repo is on) and 3.18.0, and neither has it on BufferedSource or as an extension in the okio package. I've kept readShort().toUShort().toLong() for now since it matches the count fields and SvcParam lengths above; happy to switch all the call sites over once okio grows readUShort.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. The DNS code moved to okhttp3/internal/dns on master since I opened this, so I rebased and carried the change and the regression test over to the new location. That file already imports okio.readUShort for the counts and the SvcParam lengths, so it comes out as just the one-line swap to readUShort().toLong(). Test and spotless pass on the rebased branch.

import okio.IOException
import okio.ProtocolException
import okio.Source
import okio.buffer

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import okio.buffer
import okio.readUShort

@basavaraj-sm05
basavaraj-sm05 force-pushed the dns-rdlength-unsigned branch from 1c8949c to db2a1c4 Compare July 28, 2026 11:30
@swankjesse
swankjesse merged commit 44c6993 into lysine-dev:main Jul 29, 2026
22 of 23 checks passed
@swankjesse

Copy link
Copy Markdown
Collaborator

Thank you! 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants